home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / CW GUSI 1.6.4 / src / GUSIDispatch.cp < prev    next >
Text File  |  1995-11-05  |  27KB  |  1,279 lines

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIDispatch.cp-    Dispatch calls to their correct recipient
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: GUSIDispatch.cp,v $
  8. Revision 1.4  1994/12/30  19:48:09  neeri
  9. Remove (theoretical) support for pre-System 6 systems.
  10. Remove built-in support for INETd.
  11. Fix problems in connection with ROM PowerPC library.
  12. Move open() to GUSIFileDispatch.cp.
  13. Support AF_UNSPEC domains.
  14. More work on spinning performance.
  15.  
  16. Revision 1.3  1994/08/10  00:30:30  neeri
  17. Sanitized for universal headers.
  18. Prevent overly fast spinning.
  19.  
  20. Revision 1.2  1994/05/01  23:47:34  neeri
  21. Extend fflush() kludge.
  22. Define _lastbuf for MPW 3.2 compatibility.
  23.  
  24. Revision 1.1  1994/02/25  02:28:36  neeri
  25. Initial revision
  26.  
  27. Revision 0.27  1993/11/24  00:00:00  neeri
  28. Flush stdio before closing
  29.  
  30. Revision 0.26  1993/11/22  00:00:00  neeri
  31. Extend two time loser for EBADF
  32.  
  33. Revision 0.25  1993/11/12  00:00:00  neeri
  34. Two time loser workaround for flush bug
  35.  
  36. Revision 0.24  1993/06/27  00:00:00  neeri
  37. {pre,post}_select
  38.  
  39. Revision 0.23  1993/06/27  00:00:00  neeri
  40. ftruncate
  41.  
  42. Revision 0.22  1993/06/20  00:00:00  neeri
  43. Further subtleties in console handling 
  44.  
  45. Revision 0.21  1993/05/21  00:00:00  neeri
  46. Suffixes
  47.  
  48. Revision 0.20  1993/05/15  00:00:00  neeri
  49. Try to keep errno always set on error returns
  50.  
  51. Revision 0.19  1993/05/13  00:00:00  neeri
  52. Limit Search for configuration resource to application
  53.  
  54. Revision 0.18  1993/01/31  00:00:00  neeri
  55. Introducing daemons (pleased to meet you, hope you guess my name)
  56.  
  57. Revision 0.17  1993/01/17  00:00:00  neeri
  58. Be more careful about user aborts.
  59.  
  60. Revision 0.16  1993/01/03  00:00:00  neeri
  61. GUSIConfiguration
  62.  
  63. Revision 0.15  1992/11/25  00:00:00  neeri
  64. Still trying to get standard descriptors for standalone programs right. sigh.
  65.  
  66. Revision 0.14  1992/10/05  00:00:00  neeri
  67. Small fix in event dispatching
  68.  
  69. Revision 0.13  1992/09/12  00:00:00  neeri
  70. getdtablesize()
  71.  
  72. Revision 0.12  1992/08/30  00:00:00  neeri
  73. Move hasPPC to GUSIPPC.cp, AppleTalkIdentity
  74.  
  75. Revision 0.11  1992/08/05  00:00:00  neeri
  76. Change the way standard I/O channels are opened
  77.  
  78. Revision 0.10  1992/08/03  00:00:00  neeri
  79. Move Scatter/Gather to GUSIBuffer.cp
  80.  
  81. Revision 0.9  1992/07/30  00:00:00  neeri
  82. Features with initializers
  83.  
  84. Revision 0.8  1992/07/13  00:00:00  neeri
  85. hasProcessMgr
  86.  
  87. Revision 0.7  1992/06/27  00:00:00  neeri
  88. choose(), hasNewSF
  89.  
  90. Revision 0.6  1992/06/06  00:00:00  neeri
  91. Feature
  92.  
  93. Revision 0.5  1992/04/19  00:00:00  neeri
  94. C++ Rewrite
  95.  
  96. Revision 0.4  1992/04/18  00:00:00  neeri
  97. Changed read/write/send/recv dispatchers
  98.  
  99. Revision 0.3  1992/04/17  00:00:00  neeri
  100. Spin routines
  101.  
  102. Revision 0.2  1992/04/16  00:00:00  neeri
  103. User interrupt stuff
  104.  
  105. Revision 0.1  1992/03/31  00:00:00  neeri
  106. unix domain socket calls
  107.  
  108. *********************************************************************/
  109.  
  110. #include "GUSIFile_P.h"
  111. #include "GUSIMPW_P.h"
  112. #include <SetJmp.h>
  113. #include <Signal.h>
  114. #include <CursorCtl.h>
  115. #include <Resources.h>
  116. #include <Events.h> 
  117. #include <Windows.h>
  118. #include <Desk.h>
  119. #include <Script.h>
  120. #include <OSEvents.h>
  121. #include <Traps.h>
  122. #include <CommResources.h>
  123. #include <CTBUtilities.h>
  124. #include <Connections.h>
  125. #include <FileTransfers.h>
  126. #include <Terminals.h>
  127. #include <EPPC.h>
  128. #include <PLStringFuncs.h>
  129. #include <LowMem.h>
  130. #include <Processes.h>
  131.  
  132. #if GENERATINGCFM
  133. #include <FragLoad.h>
  134. #endif
  135.  
  136. #pragma segment GUSI
  137.  
  138. /***************************** Globals ******************************/
  139.  
  140. const GUSIConfiguration GUSIConfig;        // Change the order of these declarations
  141. SocketTable                    Sockets;            //     and you'll regret it (ARM §12.6.1)
  142. GUSISpinFn                     GUSISpin     = GUSIDefaultSpin;
  143. GUSIExecFn                    GUSIExec        = GUSIDefaultExec;
  144. static GUSIEvtHandler *    evtHandler    = nil;
  145. static short                evtMask        = 0;
  146. static int                    errorSock    = -1;
  147. static int                    errorType    = 0;
  148. static int                    errorCount    = 0;
  149. const int                    errorMax        = 3;
  150. Boolean                        CatchStdIO    = false;
  151.  
  152. Feature     hasMakeFSSpec(
  153.                 gestaltFSAttr,
  154.                 (1<<gestaltHasFSSpecCalls),
  155.                 (1<<gestaltHasFSSpecCalls));
  156. Feature     hasAlias(
  157.                 gestaltAliasMgrAttr,
  158.                 (1<<gestaltAliasMgrPresent),
  159.                 (1<<gestaltAliasMgrPresent));
  160. Feature    hasNewSF(
  161.                 gestaltStandardFileAttr,
  162.                 (1<<gestaltStandardFile58),
  163.                 (1<<gestaltStandardFile58));
  164. Feature     hasProcessMgr(
  165.                 gestaltOSAttr,
  166.                 (1<<gestaltLaunchControl),
  167.                 (1<<gestaltLaunchControl));
  168. Feature hasCRM_P(
  169.                 gestaltCRMAttr,
  170.                 (1<<gestaltCRMPresent),
  171.                 (1<<gestaltCRMPresent));
  172. Feature hasCRM(hasCRM_P, InitCRM);
  173. Feature hasCTB(hasCRM, InitCTBUtilities);
  174. Feature hasStdNBP_P(
  175.                 gestaltStdNBPAttr,
  176.                 (1<<gestaltStdNBPPresent),
  177.                 (1<<gestaltStdNBPPresent));
  178. Feature hasStdNBP(hasCTB, hasStdNBP_P);
  179. Feature hasCM(hasCTB, InitCM);
  180. Feature hasFT(hasCTB, InitFT);
  181. Feature hasTM(hasCTB, InitTM);
  182. Feature hasAppleEvents(
  183.                 gestaltAppleEventsAttr,
  184.                 (1<<gestaltAppleEventsPresent),
  185.                 (1<<gestaltAppleEventsPresent));
  186. Feature hasRevisedTimeMgr(
  187.             gestaltTimeMgrVersion,
  188.             2L);
  189.  
  190. /*********************** Error propagation ************************/
  191.  
  192. #ifdef GUSI_DISPATCH
  193. inline
  194. #endif
  195. int GUSI_error(int err)
  196. {
  197.     errno =    err;
  198.  
  199.     return -1;
  200. }
  201.  
  202. #ifdef GUSI_DISPATCH
  203. inline
  204. #endif
  205. void * GUSI_error_nil(int err)
  206. {
  207.     errno =    err;
  208.  
  209.     return nil;
  210. }
  211.  
  212. /*********************** GUSIConfiguration members ************************/
  213.  
  214. #ifndef GUSI_DISPATCH
  215.  
  216. Boolean     GUSIConfiguration::firstTime = false;
  217. short        GUSIConfiguration::we;
  218.  
  219. GUSIConfiguration::GUSIConfiguration()
  220. {
  221.     typedef GUSIConfigRsrc **    GUSIConfHdl;
  222.     short    oldResFile = CurResFile();
  223.     
  224.     if (!firstTime)
  225.         we = oldResFile;
  226.     else
  227.         UseResFile(we);
  228.         
  229.     GUSIConfHdl config     =    GUSIConfHdl(Get1Resource('GU∑I', GUSIRsrcID));
  230.     long            confSize    =    config ? GetHandleSize(Handle(config)) : 0;
  231.     
  232.     if (confSize < 4 || !(defaultType = (*config)->defaultType))
  233.         defaultType    =    'TEXT';
  234.     if (confSize < 8 || !(defaultCreator = (*config)->defaultCreator))
  235.         defaultCreator    =    'MPS ';
  236.     if (confSize < 9) 
  237.         autoSpin    =    1;            // do automatic spin on read/write
  238.     else
  239.         autoSpin = (*config)->autoSpin;
  240.         
  241.     if (confSize < 10) {
  242.         noChdir    =    false;    // Use chdir()
  243.         accurStat=    false;    // st_nlink = # of entries + 2
  244.         hasConsole=    false;
  245.     } else {
  246.         noChdir        =    ((*config)->flags & 0x80) != 0;
  247.         accurStat    =    ((*config)->flags & 0x40) != 0;
  248.         hasConsole    =    ((*config)->flags & 0x08) != 0;
  249.     }
  250.     
  251.     if (confSize < 14)
  252.         version = '0102';
  253.     else
  254.         version = (*config)->version;
  255.     if (version < '0120' || confSize < 16)
  256.         numSuffices = 0;
  257.     else
  258.         numSuffices = (*config)->numSuffices;
  259.     
  260.     if (!numSuffices)
  261.         suffices = nil;
  262.     else if (suffices = new GUSISuffix[numSuffices]) {
  263.         memcpy(suffices, (*config)->suffices, numSuffices*sizeof(GUSISuffix));
  264.         for (int i=0; i<numSuffices; i++)
  265.             for (int j=0; j<4; j++)
  266.                 if (((char *) (suffices+i))[j] == ' ')
  267.                     ((char *) (suffices+i))[j] = 0;
  268.     }
  269.     
  270.     if (!firstTime) {
  271.         firstTime    =    true;
  272.         
  273.         if (!noChdir)
  274.             chdir(":");
  275.     } else
  276.         UseResFile(oldResFile);
  277. }
  278.  
  279. void GUSIConfiguration::SetDefaultFType(const TFileSpec & name) const
  280. {
  281.     FInfo    info;    
  282.  
  283.     if (HGetFInfo(name.vRefNum, name.parID, name.name, &info))
  284.         return;
  285.  
  286.     Ptr dot = PLstrrchr(name.name, '.');
  287.     
  288.     if (dot && (name.name[0] - (dot-Ptr(name.name))) <= 4) {
  289.         char searchsuffix[5];
  290.         
  291.         strncpy(searchsuffix, dot+1, name.name[0] - (dot-Ptr(name.name)));
  292.         
  293.         for (int i = 0; i<numSuffices; i++)
  294.             if (!strncmp(suffices[i].suffix, searchsuffix, 4)) {
  295.                 info.fdType     =    suffices[i].suffType;
  296.                 info.fdCreator    =    suffices[i].suffCreator;
  297.                 
  298.                 goto determined;
  299.             }
  300.     }
  301.  
  302.     info.fdType     =    defaultType;
  303.     info.fdCreator    =    defaultCreator;
  304.  
  305. determined:    
  306.     HSetFInfo(name.vRefNum, name.parID, name.name, &info);
  307. }
  308.  
  309. #endif // GUSI_DISPATCH
  310.  
  311. inline void GUSIConfiguration::DoAutoSpin() const 
  312. {
  313.     if (autoSpin)
  314.         SAFESPIN(0, SP_AUTO_SPIN, autoSpin);
  315. }
  316.  
  317. /************************ Handle nonstandard consoles *************************/
  318.  
  319. #ifndef GUSI_DISPATCH
  320.  
  321. static void InitConsole()
  322. {
  323.     if (MPWDomain::stdopen) {
  324.         for (int i = 0; i < 3; i++) {
  325.             Socket * sock =     MPWDomain::stdopen(i);
  326.  
  327.             if (sock)
  328.                 Sockets.Install(sock);
  329.         }
  330.     } else {
  331.         if (open("dev:console", O_RDONLY) < 0)
  332.             open("dev:null", O_RDONLY);
  333.         if (open("dev:console", O_WRONLY) < 0)
  334.             open("dev:null", O_WRONLY);
  335.         if (open("dev:console", O_WRONLY) < 0)
  336.             open("dev:null", O_WRONLY); 
  337.     }
  338. }
  339.  
  340. void SocketTable::InitConsole()
  341. {
  342.     if (needsConsole) {
  343.         needsConsole = false;
  344.         ::InitConsole();
  345.     }
  346. }
  347.  
  348. #endif // GUSI_DISPATCH
  349.  
  350. /************************ External routines *************************/
  351.  
  352. int getdtablesize()
  353. {
  354.     return GUSI_MAX_FD;
  355. }
  356.  
  357. int socket(int domain, int type, int protocol)
  358. {
  359.     SocketDomain *    dom;
  360.     Socket *         sock;
  361.     int                fd;
  362.  
  363.     Sockets.InitConsole();
  364.     
  365.     if (dom = SocketDomain::Domain(domain))
  366.         if (sock = dom->socket(type, protocol))
  367.             if ((fd = Sockets.Install(sock)) != -1)
  368.                 return fd;
  369.             else
  370.                 delete sock;
  371.  
  372.     if (!errno)
  373.         return GUSI_error(ENOMEM);
  374.     else
  375.         return -1;
  376. }
  377.  
  378. int choose(int domain, int type, char * prompt, void * constraint, int flags, void * name, int * namelen)
  379. {
  380.     SocketDomain *    dom;
  381.  
  382.     if (dom = SocketDomain::Domain(domain))
  383.         return dom->choose(type, prompt, constraint, flags, name, namelen);
  384.  
  385.     return -1;
  386. }
  387.  
  388. int bind(int s, const struct sockaddr *name, int namelen)
  389. {
  390.     Socket *    sock    =    Sockets[s];
  391.  
  392.     return sock ? sock->bind((void *) name, namelen) : -1;
  393. }
  394.  
  395. int connect(int s, const struct sockaddr *addr, int addrlen)
  396. {
  397.     Socket *    sock    =    Sockets[s];
  398.  
  399.     return sock ? sock->connect((void *) addr, addrlen) : -1;
  400. }
  401.  
  402. int listen(int s, int qlen)
  403. {
  404.     Socket *    sock    =    Sockets[s];
  405.  
  406.     return sock ? sock->listen(qlen) : -1;
  407. }
  408.  
  409. int accept(int s, struct sockaddr *addr, int *addrlen)
  410. {
  411.     Socket *    sock    =    Sockets[s];
  412.  
  413.     if (sock)
  414.         if (sock    = sock->accept(addr, addrlen))
  415.             if ((s = Sockets.Install(sock)) != -1)
  416.                 return s;
  417.             else
  418.                 delete sock;
  419.  
  420.     return -1;
  421. }
  422.  
  423. int close(int s)
  424. {
  425.     errorSock    =    -1;
  426.     
  427.     return Sockets.Remove(s);
  428. }
  429.  
  430. #ifdef __MWERKS__
  431. int read(int s, char *buffer, int buflen)
  432. #else
  433. int read(int s, char *buffer, unsigned buflen)
  434. #endif
  435. {
  436.     GUSIConfig.DoAutoSpin();
  437.     
  438.     Socket *    sock    =    Sockets[s];
  439.  
  440.     return sock ? sock->read(buffer, (unsigned) buflen) : -1;
  441. }
  442.  
  443. int readv(int s, const struct iovec *iov, int count)
  444. {
  445.     GUSIConfig.DoAutoSpin();
  446.     
  447.     Socket *    sock    =    Sockets[s];
  448.  
  449.     if (sock)    {
  450.         Scatterer    scatt(iov, count);
  451.  
  452.         if (scatt)
  453.             return scatt.length(sock->read(scatt.buffer(), scatt.buflen()));
  454.         else
  455.             return GUSI_error(ENOMEM);
  456.     } else
  457.         return -1;
  458. }
  459.  
  460. int recv(int s, void *buffer, int buflen, int flags)
  461. {
  462.     GUSIConfig.DoAutoSpin();
  463.     
  464.     int         fromlen     =    0;
  465.     Socket *    sock        =    Sockets[s];
  466.  
  467.     return sock ? sock->recvfrom(buffer, buflen, flags, nil, &fromlen) : -1;
  468. }
  469.  
  470. int recvfrom(int s, void *buffer, int buflen, int flags, struct sockaddr *from, int *fromlen)
  471. {
  472.     GUSIConfig.DoAutoSpin();
  473.     
  474.     Socket *    sock    =    Sockets[s];
  475.  
  476.     return sock ? sock->recvfrom(buffer, buflen, flags, from, fromlen) : -1;
  477. }
  478.  
  479. int recvmsg(int s, struct msghdr *msg, int flags)
  480. {
  481.     GUSIConfig.DoAutoSpin();
  482.     
  483.     Socket *    sock    =    Sockets[s];
  484.  
  485.     if (sock)    {
  486.         Scatterer    scatt((struct iovec *)msg->msg_iov, msg->msg_iovlen);
  487.  
  488.         if (scatt)
  489.             return
  490.                 scatt.length(
  491.                     sock->recvfrom(
  492.                         scatt.buffer(),
  493.                         scatt.buflen(),
  494.                         flags,
  495.                         msg->msg_name,
  496.                         (int *)&msg->msg_namelen));
  497.         else
  498.             return GUSI_error(ENOMEM);
  499.     } else
  500.         return -1;
  501. }
  502.  
  503. #ifdef __MWERKS__
  504. int write(int s, const char *buffer, int buflen)
  505. #else
  506. int write(int s, const char *buffer, unsigned buflen)
  507. #endif
  508. {
  509.     /* fflush() in the MPW stdio library doesn't take no for an answer.
  510.         Our workaround is to treat a second subsequent ESHUTDOWN or EBADF as 
  511.         an invitation to lie by pretending the write worked.
  512.     */
  513.     
  514.     int    len;
  515.     
  516.     GUSIConfig.DoAutoSpin();
  517.     
  518.     Socket *    sock    =    Sockets[s];
  519.  
  520.     if (sock && (len = sock->write((char *) buffer, (unsigned) buflen)) != -1)
  521.         return len;
  522.         
  523.     switch (errno) {
  524.     case EINTR:
  525.     case EWOULDBLOCK:
  526.     case EINPROGRESS:
  527.     case EALREADY:
  528.         break;
  529.     default:
  530.         if (errorSock == s && errorType == errno) {
  531.             if (++errorCount == errorMax) {
  532.                 errorSock = -1;
  533.             
  534.                 return buflen;
  535.             }
  536.         } else {
  537.             errorSock = s;
  538.             errorType = errno;
  539.             errorCount= 1;
  540.         }
  541.     }
  542.     return -1;
  543. }
  544.  
  545. int writev(int s, const struct iovec *iov, int count)
  546. {
  547.     GUSIConfig.DoAutoSpin();
  548.     
  549.     Socket *    sock    =    Sockets[s];
  550.  
  551.     if (sock)    {
  552.         Gatherer    gath(iov, count);
  553.  
  554.         if (gath)
  555.             return gath.length(sock->write(gath.buffer(), gath.buflen()));
  556.         else
  557.             return GUSI_error(ENOMEM);
  558.     } else
  559.         return -1;
  560. }
  561.  
  562. int send(int s, const void *buffer, int buflen, int flags)
  563. {
  564.     GUSIConfig.DoAutoSpin();
  565.     
  566.     Socket *    sock    =    Sockets[s];
  567.  
  568.     return sock ? sock->sendto((void *)buffer, buflen, flags, nil, 0) : -1;
  569. }
  570.  
  571. int sendto(int s, const void *buffer, int buflen, int flags, const struct sockaddr *to, int tolen)
  572. {
  573.     GUSIConfig.DoAutoSpin();
  574.     
  575.     Socket *    sock    =    Sockets[s];
  576.  
  577.     return sock ? sock->sendto((void *)buffer, buflen, flags, (void *) to, tolen) : -1;
  578. }
  579.  
  580. int sendmsg(int s, const struct msghdr *msg, int flags)
  581. {
  582.     GUSIConfig.DoAutoSpin();
  583.     
  584.     Socket *    sock    =    Sockets[s];
  585.  
  586.     if (sock)    {
  587.         Gatherer    gath((struct iovec *) msg->msg_iov, msg->msg_iovlen);
  588.  
  589.         if (gath)
  590.             return
  591.                 gath.length(
  592.                     sock->sendto(
  593.                         gath.buffer(),
  594.                         gath.buflen(),
  595.                         flags,
  596.                         msg->msg_name,
  597.                         msg->msg_namelen));
  598.         else
  599.             return GUSI_error(ENOMEM);
  600.     } else
  601.         return -1;
  602. }
  603.  
  604. int select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
  605. {
  606.     Socket    *    sock;
  607.     long             count;
  608.     int             s;
  609.     long             starttime, waittime;
  610.     fd_set         rd, wd, ed;
  611.     Boolean        r,w,e;
  612.     Boolean *    canRead;
  613.     Boolean *    canWrite;
  614.     Boolean *    exception;
  615.  
  616.     count = 0;
  617.     FD_ZERO(&rd);
  618.     FD_ZERO(&wd);
  619.     FD_ZERO(&ed);
  620.  
  621.     if (timeout)
  622.         waittime =  timeout->tv_sec*60 + timeout->tv_usec/16666;
  623.     else
  624.         waittime =    2000000000;    // Slightly more than a year; close enough to "no timeout"
  625.         
  626.     starttime = LMGetTicks();
  627.  
  628.     // Check files for kosherness
  629.  
  630.     for (s = 0; s < width ; ++s)
  631.         if (    (readfds && FD_ISSET(s,readfds))
  632.             ||    (writefds && FD_ISSET(s,writefds))
  633.             ||    (exceptfds && FD_ISSET(s,exceptfds))
  634.         )
  635.             if (!Sockets[s])
  636.                 return GUSI_error(EBADF);
  637.     
  638.     for (s = 0; s < width ; ++s)
  639.         if (sock = Sockets[s]) {
  640.             r = readfds && FD_ISSET(s,readfds);
  641.             w = writefds && FD_ISSET(s,writefds);
  642.             e = exceptfds && FD_ISSET(s,exceptfds);
  643.  
  644.             if (r || w || e)
  645.                 sock->pre_select(r, w, e);
  646.         }
  647.         
  648.     do {
  649.         for (s = 0; s < width ; ++s)  {
  650.             if (sock = Sockets[s]) {
  651.                 r = false;
  652.                 w = false;
  653.                 e = false;
  654.  
  655.                 canRead = (readfds && FD_ISSET(s,readfds)) ? &r : nil;
  656.                 canWrite = (writefds && FD_ISSET(s,writefds)) ? &w : nil;
  657.                 exception = (exceptfds && FD_ISSET(s,exceptfds)) ? &e : nil;
  658.  
  659.                 if (canRead || canWrite || exception)    {
  660.                     count    += sock->select(canRead, canWrite, exception);
  661.  
  662.                     if (r)
  663.                         FD_SET(s,&rd);
  664.                     if (w)
  665.                         FD_SET(s,&wd);
  666.                     if (e)
  667.                         FD_SET(s,&ed);
  668.                 }
  669.             }
  670.         }
  671.         if (count)
  672.             break;
  673.  
  674.         SAFESPIN(false, SP_SELECT, waittime);
  675.  
  676.         if (errno) {
  677.             count = -1;
  678.             
  679.             break;
  680.         }
  681.     }  while (LMGetTicks() - starttime < waittime);
  682.  
  683.     for (s = 0; s < width ; ++s)
  684.         if (sock = Sockets[s]) {
  685.             r = readfds && FD_ISSET(s,readfds);
  686.             w = writefds && FD_ISSET(s,writefds);
  687.             e = exceptfds && FD_ISSET(s,exceptfds);
  688.  
  689.             if (r || w || e)
  690.                 sock->post_select(r, w, e);
  691.         }
  692.         
  693.     if (count < 0)
  694.         return GUSI_error(EINTR);
  695.         
  696.     if (readfds)
  697.         *readfds = rd;
  698.     if (writefds)
  699.         *writefds = wd;
  700.     if (exceptfds)
  701.         *exceptfds = ed;
  702.  
  703.     return count;
  704. }
  705.  
  706. int getsockname(int s, struct sockaddr *name, int *namelen)
  707. {
  708.     Socket *    sock    =    Sockets[s];
  709.  
  710.     return sock ? sock->getsockname(name, namelen) : -1;
  711. }
  712.  
  713. int getpeername(int s, struct sockaddr *name, int *namelen)
  714. {
  715.     Socket *    sock    =    Sockets[s];
  716.  
  717.     return sock ? sock->getpeername(name, namelen) : -1;
  718. }
  719.  
  720. int shutdown(int s, int how)
  721. {
  722.     Socket *    sock    =    Sockets[s];
  723.  
  724.     return sock ? sock->shutdown(how) : -1;
  725. }
  726.  
  727. int fcntl(int s, unsigned int cmd, int arg)
  728. {
  729.     Socket *    sock    =    Sockets[s];
  730.  
  731.     if (sock)
  732.         return (cmd == F_DUPFD) ? Sockets.Install(sock, arg) : sock->fcntl(cmd, arg);
  733.     else
  734.         return -1;
  735. }
  736.  
  737. int dup(int s)
  738. {
  739.     Socket *    sock    =    Sockets[s];
  740.  
  741.     return sock ? Sockets.Install(sock, s) : -1;
  742. }
  743.  
  744. int dup2(int s, int s1)
  745. {
  746.     Socket *    sock    =    Sockets[s];
  747.  
  748.     if (!sock)
  749.         return -1;
  750.  
  751.     if (Sockets[s1])
  752.         Sockets.Remove(s1);
  753.  
  754.     return Sockets.Install(sock, s1);
  755. }
  756.  
  757. int ioctl(int s, unsigned int request, long *argp)
  758. {
  759.     Socket *    sock    =    Sockets[s];
  760.  
  761.     if (!sock)
  762.         return -1;
  763.     
  764.     return sock->ioctl(request, argp);
  765. }
  766.  
  767. int getsockopt(int s, int level, int optname, void *optval, int * optlen)
  768. {
  769.     Socket *    sock    =    Sockets[s];
  770.  
  771.     return sock ? sock->getsockopt(level, optname, optval, optlen) : -1;
  772. }
  773.  
  774. int setsockopt(int s, int level, int optname, const void *optval, int optlen)
  775. {
  776.     Socket *    sock    =    Sockets[s];
  777.  
  778.     return sock ? sock->setsockopt(level, optname, (void *) optval, optlen) : -1;
  779. }
  780.  
  781. int fstat(int s, struct stat * buf)
  782. {
  783.     Socket *    sock    =    Sockets[s];
  784.  
  785.     return sock ? sock->fstat(buf) : -1;
  786. }
  787.  
  788. long lseek(int s, long offset, int whence)
  789. {
  790.     Socket *    sock    =    Sockets[s];
  791.  
  792.     return sock ? sock->lseek(offset, whence) : -1;
  793. }
  794.  
  795. int ftruncate(int s, long offset)
  796. {
  797.     Socket *    sock    =    Sockets[s];
  798.  
  799.     return sock ? sock->ftruncate(offset) : -1;
  800. }
  801.  
  802. int isatty(int s)
  803. {
  804.     Socket *    sock    =    Sockets[s];
  805.  
  806.     return sock ? sock->isatty() : -1;
  807. }
  808.  
  809. void GUSISetHook(GUSIHookCode code, GUSIHook hook)
  810. {
  811.     switch (code) {
  812.     case GUSI_SpinHook:
  813.         GUSISpin = (GUSISpinFn) hook;
  814.         break;
  815.     case GUSI_ExecHook:
  816.         GUSIExec = (GUSIExecFn) hook;
  817.         break;
  818.     }
  819. }
  820.  
  821. GUSIHook GUSIGetHook(GUSIHookCode code)
  822. {
  823.     switch (code) {
  824.     case GUSI_SpinHook:
  825.         return (GUSIHook) GUSISpin;
  826.     case GUSI_ExecHook:
  827.         return (GUSIHook) GUSIExec;
  828.     default:
  829.         return (GUSIHook) nil;
  830.     }
  831. }
  832.  
  833. int GUSISetEvents(GUSIEvtTable table)
  834. {
  835.     short    evt;
  836.  
  837.     evtHandler    =    table;
  838.     evtMask        =    0;
  839.  
  840.     for (evt = 0; evt<16; ++evt)
  841.         if (evtHandler[evt])
  842.             evtMask    |=    1 << evt;
  843.  
  844.     return 0;
  845. }
  846.  
  847. GUSIEvtHandler * GUSIGetEvents(void)
  848. {
  849.     return evtHandler;
  850. }
  851.  
  852. /*********************** SocketDomain members ***********************/
  853.  
  854. #ifndef GUSI_DISPATCH
  855.  
  856. SocketDomain *            SocketDomain::domains[GUSI_MAX_DOMAIN];
  857. ProcessSerialNumber    SocketDomain::process;
  858.  
  859. SocketDomain * SocketDomain::Domain(int domain)
  860. {
  861.     if (domain < 0 || domain >= GUSI_MAX_DOMAIN || !domains[domain])    {
  862.         GUSI_error(EINVAL);
  863.  
  864.         return nil;
  865.     } else
  866.         return domains[domain];
  867. }
  868.  
  869. void SocketDomain::Ready()
  870. {
  871.     if (hasProcessMgr)
  872.         WakeUpProcess(&process);
  873. }
  874.  
  875. SocketDomain::SocketDomain(int domain)
  876. {
  877. #ifdef PREVENT_DUPLICATE_DOMAINS
  878.     if (domains[domain])    {
  879.         Str63    msg;
  880.  
  881.         sprintf((char *) msg+1, "Duplicate declaration for domain %d\n", domain);
  882.         msg[0] = (unsigned char)strlen((char *) msg+1);
  883.  
  884.         DebugStr(msg);
  885.     }
  886. #endif
  887.     if (domain)                                    // Ignore AF_UNSPEC domains
  888.         domains[domain]    =    this;
  889.     
  890.     if (hasProcessMgr && !process.highLongOfPSN && !process.lowLongOfPSN)
  891.         GetCurrentProcess(&process);
  892. }
  893.  
  894. SocketDomain::~SocketDomain()
  895. {
  896. }
  897.  
  898. // Default implementations of socket() just returns an error
  899.  
  900. Socket * SocketDomain::socket(int, short)
  901. {
  902.     GUSI_error(EOPNOTSUPP);
  903.  
  904.     return nil;
  905. }
  906.  
  907. int SocketDomain::choose(int, char *, void *, int, void *, int *)
  908. {
  909.     return GUSI_error(EOPNOTSUPP);
  910. }
  911.  
  912. void SocketDomain::DontStrip()
  913. {
  914. }
  915.  
  916. /*********************** SocketTable members ************************/
  917.  
  918. static void FlushStdio()
  919. {
  920.     fwalk(fflush);
  921. }
  922.  
  923. SocketTable::SocketTable()
  924. {
  925.     atexit(FlushStdio);
  926.     
  927.     needsConsole = true;
  928. }
  929.     
  930. int SocketTable::Install(Socket * sock, int start)
  931. {
  932.     short    fd;
  933.  
  934.     if (start<0 || start >= GUSI_MAX_FD)
  935.         return GUSI_error(EINVAL);
  936.  
  937.     for (fd=start; fd<GUSI_MAX_FD; ++fd)
  938.         if (!sockets[fd])    {
  939.             sockets[fd] = sock;
  940.         
  941.             ++sock->refCount;
  942.             return fd;
  943.         }
  944.  
  945.     return GUSI_error(EMFILE);
  946. }
  947.  
  948. int SocketTable::Remove(int fd)
  949. {
  950.     Socket *    sock;
  951.  
  952.     InitConsole();
  953.  
  954.     if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd]))
  955.         return GUSI_error(EBADF);
  956.  
  957.     sockets[fd]     =    nil;
  958.  
  959.     if (!--sock->refCount)
  960.         delete sock;
  961.  
  962.     return 0;
  963. }
  964.  
  965. Socket * SocketTable::operator[](int fd)
  966. {
  967.     Socket * sock;
  968.  
  969.     InitConsole();
  970.     
  971.     if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd]))    {
  972.         GUSI_error(EBADF);
  973.  
  974.         return nil;
  975.     } else
  976.         return sock;
  977. }
  978.  
  979. #pragma far_code
  980.  
  981. SocketTable::~SocketTable()
  982. {
  983.     int i;
  984.  
  985.     // Flush stdio files (necessary to flush buffers)
  986.  
  987.     fwalk(fflush);
  988.  
  989.     // If we didn't need a console so far, we certainly don't need one now!
  990.     // Doing this further up would be dangerous for small write only apps
  991.     
  992.     needsConsole = false;
  993.  
  994.     // Now close stdio files, just to be sure
  995.  
  996.     fwalk(fclose);
  997.  
  998.     // Close all files
  999.  
  1000.     for (i = 0; i<GUSI_MAX_FD; ++i)
  1001.         if (sockets[i])
  1002.             close(i);
  1003. }
  1004.  
  1005. #pragma smart_code
  1006.  
  1007. /********************** sleep()/alarm() ***********************/
  1008.  
  1009. static long    GUSIAlarm = 0;
  1010.  
  1011. int GUSICheckAlarm()
  1012. {
  1013.     if (GUSIAlarm && LMGetTicks() > GUSIAlarm) {
  1014.         GUSIAlarm = 0;
  1015.         raise(SIGALRM);
  1016.         
  1017.         return 1;
  1018.     } else
  1019.         return 0;
  1020. }
  1021.  
  1022. u_int     alarm(u_int seconds)
  1023. {
  1024.     long remaining = GUSIAlarm ? (LMGetTicks() - GUSIAlarm) / 60 : 0;
  1025.     
  1026.     GUSIAlarm = seconds ? LMGetTicks() + 60 * seconds : 0;
  1027.     
  1028.     return (remaining < 0) ? 0 : (u_int) remaining;
  1029. }
  1030.  
  1031. static u_int DoSleep(long ticks)
  1032. {
  1033.     long wakeup = LMGetTicks() + ticks;
  1034.     
  1035.     SAFESPIN(wakeup > LMGetTicks(), SP_SLEEP, wakeup - LMGetTicks());
  1036.     
  1037.     long remaining = (LMGetTicks() - wakeup) / 60;
  1038.     
  1039.     return (remaining < 0) ? 0 : (u_int) remaining;
  1040. }
  1041.  
  1042. u_int sleep(u_int seconds) 
  1043. {
  1044.     return DoSleep(seconds * 60);
  1045. }
  1046.  
  1047. void usleep(u_int useconds)
  1048. {
  1049.     DoSleep((useconds * 3) / 50000);
  1050. }
  1051.  
  1052. /********************** Default spin function ***********************/
  1053.  
  1054. /* Borrowed from tech note 263 */
  1055.  
  1056. #define kMaskModifiers      0xFE00         // we need the modifiers without the
  1057.                                            // command key for KeyTrans
  1058. #define kMaskVirtualKey     0x0000FF00     // get virtual key from event message
  1059.                                            // for KeyTrans
  1060. #define kUpKeyMask          0x0080
  1061. #define kShiftWord          8              // we shift the virtual key to mask it
  1062.                                            // into the keyCode for KeyTrans
  1063. #define kMaskASCII1         0x00FF0000     // get the key out of the ASCII1 byte
  1064. #define kMaskASCII2         0x000000FF     // get the key out of the ASCII2 byte
  1065. #define kPeriod             0x2E           // ascii for a period
  1066.  
  1067. static Boolean CmdPeriod(EventRecord *theEvent)
  1068. {
  1069.       Boolean  fTimeToQuit;
  1070.       short    keyCode;
  1071.       long     virtualKey, keyInfo, lowChar, highChar, keyCId;
  1072.       UInt32    state;
  1073.       Handle   hKCHR;
  1074.     Ptr         KCHRPtr;
  1075.  
  1076.     fTimeToQuit = false;
  1077.  
  1078.     if (((*theEvent).what == keyDown) || ((*theEvent).what == autoKey)) {
  1079.  
  1080.         // see if the command key is down.  If it is, find out the ASCII
  1081.         // equivalent for the accompanying key.
  1082.  
  1083.         if ((*theEvent).modifiers & cmdKey ) {
  1084.  
  1085.             virtualKey = ((*theEvent).message & kMaskVirtualKey) >> kShiftWord;
  1086.             // And out the command key and Or in the virtualKey
  1087.             keyCode    = short(((*theEvent).modifiers & kMaskModifiers) | virtualKey);
  1088.             state      = 0;
  1089.  
  1090.             hKCHR = nil;  /* set this to nil before starting */
  1091.              KCHRPtr = (Ptr)GetEnvirons(smKCHRCache);
  1092.  
  1093.             if ( !KCHRPtr ) {
  1094.                 keyCId = GetScript(short(GetEnvirons(smKeyScript)), smScriptKeys);
  1095.  
  1096.                 hKCHR   = GetResource('KCHR',short(keyCId));
  1097.                 KCHRPtr = *hKCHR;
  1098.             }
  1099.  
  1100.             if (KCHRPtr) {
  1101.                 keyInfo = KeyTrans(KCHRPtr, keyCode, &state);
  1102.                 if (hKCHR)
  1103.                     ReleaseResource(hKCHR);
  1104.             } else
  1105.                 keyInfo = (*theEvent).message;
  1106.  
  1107.             lowChar =  keyInfo &  kMaskASCII2;
  1108.             highChar = (keyInfo & kMaskASCII1) >> 16;
  1109.             if (lowChar == kPeriod || highChar == kPeriod)
  1110.                 fTimeToQuit = true;
  1111.  
  1112.         }  // end the command key is down
  1113.     }  // end key down event
  1114.  
  1115.     return( fTimeToQuit );
  1116. }
  1117.  
  1118. Boolean GUSIInterrupt()
  1119. {
  1120.     EvQElPtr        eventQ;
  1121.  
  1122.     for (eventQ = (EvQElPtr) LMGetEventQueue()->qHead; eventQ; )
  1123.         if (CmdPeriod((EventRecord *) &eventQ->evtQWhat))
  1124.             return true;
  1125.         else
  1126.             eventQ = (EvQElPtr)eventQ->qLink;
  1127.     
  1128.     return false;
  1129. }
  1130.  
  1131. int GUSIDefaultSpin(spin_msg msg, long arg)
  1132. {
  1133.     static Boolean            inForeground    =    true;
  1134.     WindowPtr                win;
  1135.     EventRecord                ev;
  1136.     long                        sleepTime         =    6;    // 1/10 of a second by default
  1137.  
  1138.     if (inForeground)
  1139.         SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
  1140.  
  1141.     if (GUSIInterrupt())
  1142.         goto interrupt;
  1143.  
  1144.     switch (msg) {
  1145.     case SP_SLEEP:
  1146.     case SP_SELECT:
  1147.         if (arg >= sleepTime)                // Only sleep if patience guaranteed
  1148.             break;
  1149.         // Otherwise, fall through    
  1150.     case SP_AUTO_SPIN:
  1151.         sleepTime = 1;
  1152.         break;
  1153.     default:
  1154.         break;
  1155.     }
  1156.     
  1157.     if (WaitNextEvent(osMask|highLevelEventMask|mDownMask|evtMask, &ev, sleepTime, nil))
  1158.         switch (ev.what) {
  1159.         case mouseDown:
  1160.             if (!evtHandler || !evtHandler[mouseDown])
  1161.                 if (FindWindow(ev.where, &win) == inSysWindow)
  1162.                     SystemClick(&ev, win);
  1163.  
  1164.             break;
  1165.         case osEvt:
  1166.             if (ev.message & 1)
  1167.                 inForeground    =    true;
  1168.             else
  1169.                 inForeground    =    false;
  1170.             break;
  1171.         case kHighLevelEvent:
  1172.             if (!evtHandler || !evtHandler[kHighLevelEvent])
  1173.                 if (hasAppleEvents)                // actually pretty likely, if we get HL Events
  1174.                     AEProcessAppleEvent(&ev);    // Ignore errors
  1175.             break;
  1176.         default:
  1177.             break;
  1178.         }
  1179.  
  1180.     if (ev.what >= 0 && ev.what < 24 && evtHandler && evtHandler[ev.what])
  1181.         evtHandler[ev.what](&ev);
  1182.  
  1183.     return 0;
  1184.  
  1185. interrupt:
  1186.     FlushEvents(-1, 0);
  1187.  
  1188.     return -1;
  1189. }
  1190.  
  1191. /************************** Feature members **************************/
  1192.  
  1193. Feature::Feature(unsigned short trapNum, TrapType tTyp)
  1194. {
  1195.     good =
  1196.         NGetTrapAddress(trapNum, tTyp) != NGetTrapAddress(_Unimplemented, ToolTrap);
  1197. }
  1198.  
  1199. Feature::Feature(OSType type, long value)
  1200. {
  1201.     long        attr;
  1202.  
  1203.     good = (!Gestalt(type, &attr) && (attr >= value));
  1204. }
  1205.  
  1206. Feature::Feature(OSType type, long mask, long value)
  1207. {
  1208.     long        attr;
  1209.  
  1210.     good = (!Gestalt(type, &attr) && ((attr & mask) == value));
  1211. }
  1212.  
  1213. Feature::Feature(const Feature & precondition, OSErrInitializer init)
  1214. {
  1215.     good    =    precondition && !init();
  1216. }
  1217.  
  1218. Feature::Feature(OSErrInitializer init)
  1219. {
  1220.     good    =    !init();
  1221. }
  1222.  
  1223. Feature::Feature(const Feature & precondition, voidInitializer init)
  1224. {
  1225.     if (precondition)    {
  1226.         good = true;
  1227.         init();
  1228.     } else
  1229.         good = false;
  1230. }
  1231.  
  1232. Feature::Feature(voidInitializer init)
  1233. {
  1234.     good = true;
  1235.     init();
  1236. }
  1237.  
  1238. Feature::Feature(const Feature & cond1, const Feature & cond2)
  1239. {
  1240.     good = cond1 && cond2;
  1241. }
  1242.  
  1243. OSErr AppleTalkIdentity(short & net, short & node)
  1244. {
  1245.     static short    mynet;
  1246.     static short    mynode;
  1247.     static OSErr    err = 1;
  1248.  
  1249.     if (err == 1)
  1250.         if (!(err = MPPOpen()))
  1251.             err = GetNodeAddress(&mynode, &mynet);
  1252.  
  1253.  
  1254.     net    =    mynet;
  1255.     node    =    mynode;
  1256.  
  1257.     return err;
  1258. }
  1259.  
  1260. /************************** Setup suppport **************************/
  1261.  
  1262. /* Pray that the following function never inlines GUSISetup */
  1263.  
  1264. void GUSIDefaultSetup()
  1265. {
  1266.     GUSISetup(GUSIwithAppleTalkSockets);
  1267.     GUSISetup(GUSIwithInternetSockets);
  1268.     GUSISetup(GUSIwithPAPSockets);
  1269.     GUSISetup(GUSIwithPPCSockets);
  1270.     GUSISetup(GUSIwithUnixSockets);
  1271.     GUSISetup(GUSIwithSIOUXSockets);
  1272. }
  1273.  
  1274. void GUSISetup(void (*proc)())
  1275. {
  1276.     proc();
  1277. }
  1278.  
  1279. #endif // GUSI_DISPATCH